傳遞機制聽起來非常沒有畫面感,於是擅自替傳遞機制取了綽號叫迴力鏢,如同迴力鏢有去程,回程以及獵捕到獵物的瞬間。事件傳遞機制也分成類似的三個階段:
下圖是W3C的事件流程圖,此圖說明了當使用者點擊td
時,Event Object會由Window一路傳遞到td
的父層tr
,這個過程稱作capture phase,接著到達觸發事件的元素則是target phase,從event target一路回傳的過程則稱為bubbling phase
圖片來源:W3C
為了驗證規範,還是來實做一次吧~( codepen連結 )
以下先在 html 內各個元素各自綁定事件監聽器,每當元素被點擊,就會跳出視窗告知是哪個元素被點擊以及是在事件流程的哪個階段
const elements = document.querySelectorAll('*')
for (let element of elements) {
element.addEventListener('click', e => alert(`phase: ${e.eventPhase}, ${element.tagName}`))
}
如果夠仔細的話,會發現不管點擊哪個元素,視窗都沒有跳出第一個階段,這是為什麼呢?
還記得昨天有提到addEventListener()的第三個引數嗎?
當沒有傳入值
或設定為false
時,代表的是我們把監聽器加到bubbling phase上,只要再多添加一個監聽器,並將第三個引數設定為true,當點擊元素時就可以觀察到完整的迴力鏢過程了。
觀察每個介紹事件委派的例子,一定都會提到的狀況就是要對大量的相同元素綁定事件監聽,或是後來新增的元素也需要因應使用者的行為而給予設計好的流程等等。
聰明的程式好手想到的解法便是透過父節點來處理子節點。
對我來說,事件委派的核心精神就是「能坐就不站,能躺就不坐,能做一次的事就不做兩次」。
一開始常常搞不清楚下面三個名詞的差別,在練習的過程中才逐漸察覺如果沒有使用事件委派的話,其實這三個名詞代表的會是同一個元素,但一旦有使用到事件委派,它們各自代表的元素就可能會有如下的差別:
event.target
: 代表觸發事件的元素event.currentTarget/ this
: 代表設置監聽器的元素如果有同樣困擾的朋友可以搭配 codepen 觀察,相信會清楚許多~
參考資料:
Event order
DOM Event Architecture - W3C
Bubbling and capturing - JAVASCRIPT.INFO
DOM 的事件傳遞機制:捕獲與冒泡